home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / quicktime / quicktimeintro / wiredsprites / common files / winframework.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-06  |  29.6 KB  |  991 lines

  1. //////////
  2. //
  3. //    File:        WinFramework.c
  4. //
  5. //    Contains:    Code for the QuickTime sample code framework that is specific to Windows. 
  6. //                This code handles windows, menus, events, and other low-level things. Put your
  7. //                application-specific code into the file ComApplication.c. 
  8. //
  9. //    Written by:    Tim Monroe
  10. //                Based on the QTShell code written by Tim Monroe, which in turn was based on the MDIPlayer
  11. //                code written by Brian S. Friedkin (Aug 5, 1996). This current version is now very far removed from
  12. //                MDIPlayer.
  13. //
  14. //    Copyright:    © 1999 by Apple Computer, Inc., all rights reserved.
  15. //
  16. //    Change History (most recent first):
  17. //
  18. //       <7>         04/03/00    rtm        reworked QTFrame_CalcWindowMinMaxInfo; disabled movie window maximize button
  19. //                                    in WM_CREATE message processing (implementing this is left as an exercise...)
  20. //       <6>         01/14/00    rtm        reworked window-drawing code (WM_PAINT message) to support graphics files
  21. //       <5>         01/05/00    rtm        minor tweaks to QuickTime initialization in WinMain
  22. //       <4>         12/26/99    rtm        added WM_LBUTTONDOWN processing to QTFrame_MovieWndProc; minor reorganization
  23. //                                    of QTFrame_MovieWndProc so that myMacEvent and myIsHandled are in scope for
  24. //                                    that message
  25. //       <3>         12/16/99    rtm        made minor change to QTFrame_MovieWndProc so that QTApp_HandleEvent is called
  26. //                                    even if the window has no movie controller
  27. //       <2>         11/29/99    rtm        modified "Save changes" dialog box to use Macintosh wordings prompted by move
  28. //                                    to Navigation Services
  29. //       <1>         11/05/99    rtm        first file; based on earlier sample code
  30. //       
  31. //////////
  32.  
  33. //////////
  34. //
  35. // header files
  36. //
  37. //////////
  38.  
  39. #include "WinFramework.h"
  40.  
  41.  
  42. //////////
  43. //
  44. // global variables
  45. //
  46. //////////
  47.  
  48. BOOL                gShuttingDown = false;                // are we shutting down?
  49. BOOL                gWeAreSizingWindow = false;            // are we resizing a window?
  50. BOOL                gWeAreCreatingWindow = false;        // are we creating a window?
  51.  
  52. HANDLE                ghInst;                                // the instance of this application
  53. HWND                ghWnd;                                // the MDI frame window; this window has the menu bar
  54. HWND                ghWndMDIClient;                     // the MDI client window
  55.  
  56. char                gChildName[] = "QTShellChild";
  57. char                gMovieType[] = "QuickTime Movie";
  58.  
  59. short                 gAppResFile = kInvalidFileRefNum;    // file reference number for this application's resource file
  60. FSSpec                gAppFSSpec;                            // file specification for the application itself
  61. char                gAppName[20];                        // the name of this application
  62.  
  63. LPSTR                gCmdLine;                            // the command line passed to WinMain
  64.  
  65. extern Rect            gMCResizeBounds;                    // maximum size for any movie window
  66.  
  67.  
  68. //////////
  69. //
  70. // WinMain
  71. // The main function for this application.
  72. //
  73. // Set up the application's execution environment; make sure QuickTime (etc.) is installed,
  74. // then start handling events. If we terminate before reaching the message loop, we should
  75. // return 0.
  76. //
  77. //////////
  78.  
  79. int CALLBACK WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR theCmdLine, int nCmdShow)
  80. {
  81.     HANDLE                myAccel;
  82.     HWND                myWindowFrame;
  83.     MSG                    myMsg;
  84.     WNDCLASSEX            myWC;
  85.     char                myFileName[MAX_PATH];
  86.     DWORD                myLength;
  87.     OSErr                myErr = noErr;
  88.  
  89.     ghInst = hInstance;
  90.     gCmdLine = theCmdLine;
  91.     
  92.     if (hPrevInstance == NULL) {
  93.         LoadString(hInstance, IDS_APPNAME, gAppName, sizeof(gAppName));
  94.         
  95.         // register the frame window class
  96.         myWC.cbSize        = sizeof(WNDCLASSEX);
  97.         myWC.style         = CS_HREDRAW | CS_VREDRAW;
  98.         myWC.lpfnWndProc   = (WNDPROC)QTFrame_FrameWndProc;
  99.         myWC.cbClsExtra    = 0;
  100.         myWC.cbWndExtra    = 0;
  101.         myWC.hInstance     = hInstance;
  102.         myWC.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_APPICON));
  103.         myWC.hCursor       = LoadCursor(NULL, IDC_ARROW);
  104.         myWC.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  105.         myWC.lpszMenuName  = gAppName;
  106.         myWC.lpszClassName = gAppName;
  107.         myWC.hIconSm       = LoadImage(hInstance, MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 16, 16, 0);
  108.                                      
  109.         if (!RegisterClassEx(&myWC)) {
  110.             if (!RegisterClass((LPWNDCLASS)&myWC.style))
  111.                 return(0);
  112.         }
  113.  
  114.         // register the movie child window class
  115.         myWC.cbSize        = sizeof(WNDCLASSEX);
  116.         myWC.style         = 0;
  117.         myWC.lpfnWndProc   = (WNDPROC)QTFrame_MovieWndProc;
  118.         myWC.cbClsExtra    = 0;
  119.         myWC.cbWndExtra    = 0;
  120.         myWC.hInstance     = hInstance;
  121.         myWC.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CHILDICON));
  122.         // to avoid having QuickTime VR "fight" with the system over the cursor,
  123.         // we set the client area cursor to NULL; this means that for QuickTime
  124.         // movies, we'll need to change the cursor to an arrow manually; see the
  125.         // handling of the WM_MOUSEMOVE message in QTFrame_MovieWndProc
  126.         myWC.hCursor       = NULL;
  127.         myWC.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  128.         myWC.lpszMenuName  = NULL;
  129.         myWC.lpszClassName = gChildName;
  130.         myWC.hIconSm       = LoadImage(hInstance, MAKEINTRESOURCE(IDI_CHILDICON), IMAGE_ICON, 16, 16, 0);
  131.                                      
  132.         if (!RegisterClassEx(&myWC)) {
  133.             if (!RegisterClass((LPWNDCLASS)&myWC.style))
  134.                 return(0);
  135.         }
  136.     }
  137.  
  138.     // load accelerators
  139.     myAccel = LoadAccelerators(hInstance, gAppName);
  140.  
  141.     // initialize QuickTime Media Layer and QuickTime; alert the user and return 0 if unsuccessful
  142.     myErr = InitializeQTML(0L);
  143.     if (myErr != noErr) {
  144.         MessageBox(NULL, "QuickTime is not installed on this computer. Exiting.", gAppName, MB_OK | MB_APPLMODAL);
  145.         return(0);
  146.     }
  147.     
  148.     myErr = EnterMovies();
  149.     if (myErr != noErr) {
  150.         MessageBox(NULL, "Could not initialize QuickTime. Exiting.", gAppName, MB_OK | MB_APPLMODAL);
  151.         return(0);
  152.     }
  153.  
  154.     // get the application's resource file, if it exists
  155.     myLength = GetModuleFileName(NULL, myFileName, MAX_PATH);        // NULL means: the current process
  156.     if (myLength != 0) {
  157.         NativePathNameToFSSpec(myFileName, &gAppFSSpec, kFullNativePath);
  158.  
  159.         gAppResFile = FSpOpenResFile(&gAppFSSpec, fsRdWrPerm);
  160.         if (gAppResFile != kInvalidFileRefNum)
  161.             UseResFile(gAppResFile);
  162.     }
  163.  
  164.     // do any application-specific initialization that must occur before the frame window is created
  165.     QTApp_Init(kInitAppPhase_BeforeCreateFrameWindow);
  166.     
  167.     // create the main frame window
  168.     myWindowFrame = CreateWindow(gAppName, gAppName, WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
  169.                                        CW_USEDEFAULT, 
  170.                                        CW_USEDEFAULT,
  171.                                      CW_USEDEFAULT, 
  172.                                      CW_USEDEFAULT,
  173.                                      NULL, 
  174.                                      NULL, 
  175.                                      hInstance, 
  176.                                      NULL);
  177.     ghWnd = myWindowFrame;
  178.     
  179.     // make sure we got a frame window
  180.     if (myWindowFrame == NULL)
  181.         return(0);
  182.         
  183.     // show the window
  184.     ShowWindow(myWindowFrame, nCmdShow);
  185.     UpdateWindow(myWindowFrame);
  186.     
  187.     // do any application-specific initialization that must occur after the frame window is created
  188.     QTApp_Init(kInitAppPhase_AfterCreateFrameWindow);
  189.     
  190.     // get and process events until the user quits
  191.     while (GetMessage(&myMsg, NULL, 0, 0)) {    
  192.         if (!TranslateMDISysAccel(ghWndMDIClient, &myMsg)) {
  193.             if (!TranslateAccelerator(myWindowFrame, myAccel, &myMsg)) {
  194.                 TranslateMessage(&myMsg);
  195.                 DispatchMessage(&myMsg);
  196.             }
  197.         }
  198.     }
  199.  
  200.     // close the application's resource file, if it was previously opened
  201.     if (gAppResFile != kInvalidFileRefNum)
  202.         CloseResFile(gAppResFile);
  203.  
  204.     // terminate the QuickTime Media Layer
  205.     ExitMovies();
  206.     TerminateQTML();
  207.  
  208.     return(myMsg.wParam);            // returns the value from PostQuitMessage
  209. }
  210.  
  211.  
  212. //////////
  213. //
  214. // QTFrame_FrameWndProc
  215. // The window procedure for the MDI frame window.
  216. //
  217. //////////
  218.  
  219. LRESULT CALLBACK QTFrame_FrameWndProc (HWND theWnd, UINT theMessage, UINT wParam, LONG lParam)
  220. {
  221.     HWND                   myChild;
  222.  
  223.     switch (theMessage) {
  224.     
  225.         case WM_CREATE: {
  226.             CLIENTCREATESTRUCT        myClientStruct = {0};
  227.  
  228.             myClientStruct.hWindowMenu  = GetSubMenu(GetMenu(theWnd), WINDOWMENU);
  229.             myClientStruct.idFirstChild = IDM_WINDOWCHILD;
  230.             
  231.             // create the MDI client filling the client area
  232.             ghWndMDIClient = CreateWindow("mdiclient",
  233.                                          NULL,
  234.                                          WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL,
  235.                                          0, 0, 0, 0,
  236.                                          theWnd,
  237.                                          (HMENU)0xCAC,
  238.                                          ghInst,
  239.                                          (LPVOID)&myClientStruct);
  240.             
  241.             // set initial menu state
  242.             QTFrame_AdjustMenus(NULL, GetMenu(theWnd));
  243.             
  244.             if (ghWndMDIClient != NULL)
  245.                 ShowWindow(ghWndMDIClient, SW_SHOW);
  246.             
  247.             return(0);
  248.         }
  249.  
  250.         case WM_ACTIVATE:
  251.             // the MDI frame window is being activated or deactivated;
  252.             // activate or deactivate any active child window by sending this message to DefMDIChildProc 
  253.             myChild = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L);
  254.             if (IsWindow(myChild))
  255.                 SendMessage(myChild, WM_ACTIVATE, wParam, lParam);
  256.             break;
  257.  
  258.         case WM_COMMAND: {
  259.  
  260.             switch (LOWORD(wParam)) {
  261.                 case IDM_FILENEW:
  262.                 case IDM_FILEOPEN:
  263.                 case IDM_FILECLOSE:
  264.                 case IDM_EXIT:
  265.                     QTFrame_HandleFileMenuItem(NULL, LOWORD(wParam));
  266.                     return(0);
  267.  
  268.                 case IDM_FILESAVE:
  269.                 case IDM_FILESAVEAS:
  270.                     // save the active child window
  271.                     myChild = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L);
  272.                     if (IsWindow(myChild))
  273.                         SendMessage(myChild, WM_COMMAND, wParam, lParam);
  274.                     return(0);
  275.  
  276.                 case IDM_WINDOWTILE:
  277.                     SendMessage(ghWndMDIClient, WM_MDITILE, 0, 0L);
  278.                     return(0);
  279.  
  280.                 case IDM_WINDOWCASCADE:
  281.                     SendMessage(ghWndMDIClient, WM_MDICASCADE, 0, 0L);
  282.                     return(0);
  283.  
  284.                 case IDM_WINDOWICONS:
  285.                     SendMessage(ghWndMDIClient, WM_MDIICONARRANGE, 0, 0L);
  286.                     return(0);
  287.  
  288.                 case IDM_WINDOWCLOSEALL: {
  289.                     WindowReference        myWindow, myNextWindow;
  290.             
  291.                     // walk the window list and destroy any open windows
  292.                     myWindow = QTFrame_GetFrontMovieWindow();
  293.                     while (myWindow != NULL) {
  294.                         myNextWindow = QTFrame_GetNextMovieWindow(myWindow);
  295.                         SendMessage(myWindow, WM_CLOSE, 0L, 0L);
  296.                         myWindow = myNextWindow;
  297.                     }
  298.                     
  299.                     return(0);
  300.                 }
  301.  
  302.                 case IDM_ABOUT:
  303.                     QTFrame_ShowAboutBox();
  304.                     return(0);
  305.  
  306.                 default:                
  307.                     // pass this message to the active child window...
  308.                     myChild = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L);
  309.                     if (IsWindow(myChild))
  310.                         SendMessage(myChild, WM_COMMAND, wParam, lParam);
  311.  
  312.                     // ...then do any application-specific menu handling, if no movie windows are open...
  313.                     if (myChild == NULL)
  314.                         QTApp_HandleMenu((UInt16)LOWORD(wParam));
  315.                     
  316.                     // ...and then pass it to DefFrameProc
  317.                     break;
  318.             }
  319.             break;
  320.         }
  321.  
  322.         case WM_OPENDROPPEDFILES:
  323.             // open any movie files that were dropped onto the application icon
  324.             QTFrame_OpenCommandLineMovies(gCmdLine);
  325.             return(0);
  326.  
  327.         case WM_INITMENU:
  328.             if (GetMenu(theWnd) == (HMENU)wParam)
  329.                 return(QTFrame_AdjustMenus((HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L), (HMENU)wParam));
  330.             return(1);
  331.  
  332.         case WM_CLOSE:
  333.             // if we're not already in the process of shutting down,
  334.             // simulate the selection of the Quit menu command
  335.             if (!gShuttingDown) {
  336.                 SendMessage(ghWnd, WM_COMMAND, IDM_EXIT, 0L);
  337.                 return(0);
  338.             }
  339.             break;
  340.             
  341.         case WM_DESTROY:
  342.             // do any application-specific shutdown
  343.             QTApp_Stop(kStopAppPhase_AfterDestroyWindows);
  344.             PostQuitMessage(0);
  345.             break;
  346.     }
  347.     
  348.     return(DefFrameProc(theWnd, ghWndMDIClient, theMessage, wParam, lParam));
  349. }
  350.  
  351.  
  352. //////////
  353. //
  354. // QTFrame_MovieWndProc
  355. // The window procedure for a movie window.
  356. //
  357. //////////
  358.  
  359. LRESULT CALLBACK QTFrame_MovieWndProc (HWND theWnd, UINT theMessage, UINT wParam, LONG lParam)
  360. {
  361.     WPARAM                myWidth, myHeight;
  362.     MovieController        myMC = NULL;
  363.     Movie                myMovie = NULL;
  364.     WindowObject        myWindowObject = NULL;
  365.     MSG                    myMsg = {0};
  366.     EventRecord            myMacEvent;
  367.     Boolean                myIsHandled = false;
  368.  
  369.     // get the window object, movie, and movie controller for this window
  370.     myWindowObject = QTFrame_GetWindowObjectFromWindow(theWnd);
  371.     if (myWindowObject != NULL) {
  372.         myMC = (**myWindowObject).fController;
  373.         myMovie = (**myWindowObject).fMovie;
  374.     }
  375.  
  376.     // give the movie controller this message first
  377.     if (!gShuttingDown) {
  378.         LONG            myPoints = GetMessagePos();
  379.  
  380.         myMsg.hwnd = theWnd;
  381.         myMsg.message = theMessage;
  382.         myMsg.wParam = wParam;
  383.         myMsg.lParam = lParam;
  384.         myMsg.time = GetMessageTime();
  385.         myMsg.pt.x = LOWORD(myPoints);
  386.         myMsg.pt.y = HIWORD(myPoints);
  387.  
  388.         // translate a Windows event to a Mac event
  389.         WinEventToMacEvent(&myMsg, &myMacEvent);
  390.  
  391.         // let the application-specific code have a chance to intercept the event
  392.         myIsHandled = QTApp_HandleEvent(&myMacEvent);
  393.         
  394.         // pass the Mac event to the movie controller, but only if the movie window isn't minimized
  395.         if (!myIsHandled)
  396.             if (myMC != NULL)
  397.                 if (!IsIconic(theWnd))
  398.                     myIsHandled = MCIsPlayerEvent(myMC, (EventRecord *)&myMacEvent);
  399.     }
  400.  
  401.     switch (theMessage) {
  402.         case WM_CREATE: {
  403.                 LONG        myStyles;
  404.                 
  405.                 // create a new window object associated with the new window
  406.                 QTFrame_CreateWindowObject(theWnd);
  407.             
  408.                 // disable the maximize button
  409.                 myStyles = GetWindowLong(theWnd, GWL_STYLE);
  410.                 myStyles &= ~WS_MAXIMIZEBOX;
  411.                 SetWindowLong(theWnd, GWL_STYLE, myStyles);
  412.             }
  413.             break;
  414.  
  415.         case WM_WINDOWPOSCHANGING:
  416.             // don't show the window until we have created a movie and
  417.             // can therefore properly size the window to contain the movie
  418.             if (gWeAreCreatingWindow) {
  419.                 WINDOWPOS    *lpWindowPos = (WINDOWPOS*)lParam;
  420.                 
  421.                 lpWindowPos->flags &= ~SWP_SHOWWINDOW;
  422.             }
  423.             break;
  424.  
  425.         case WM_WINDOWPOSCHANGED:
  426.             // if a movie window has become minimized, stop the movie
  427.             if (IsIconic(theWnd))
  428.                 StopMovie(myMovie);
  429.             break;
  430.  
  431.         case WM_SIZE:
  432.             // resize the movie and controller to fit the window
  433.             myWidth = LOWORD(lParam);
  434.             myHeight = HIWORD(lParam);
  435.             
  436.             // we do NOT want to resize the movie controller if the window is minimized,
  437.             // if there is no movie controller, or if we are in the middle of resizing the window
  438.             if (!gWeAreSizingWindow && (myMC != NULL) && (wParam != SIZE_MINIMIZED)) {
  439.                 Rect        myRect;
  440.                 
  441.                 myRect.top = 0;
  442.                 myRect.left = 0;
  443.                 myRect.right = myWidth;
  444.                 myRect.bottom = myHeight;
  445.                 
  446.                 MCSetControllerBoundsRect(myMC, &myRect);
  447.             }
  448.             break;
  449.  
  450.         case WM_MOUSEMOVE:
  451.             // for QuickTime movies (but NOT for QuickTime VR movies), set the cursor to the arrow cursor
  452.             if (myWindowObject != NULL)
  453.                 if (!(**myWindowObject).fIsQTVRMovie)
  454.                     SetCursor(LoadCursor(NULL, IDC_ARROW));
  455.             break;
  456.  
  457.         case WM_PUMPMOVIE:
  458.             // we receive this message only to task the movie
  459.             break;
  460.  
  461.         case WM_LBUTTONDOWN:
  462.             // do any application-specific mouse-button handling, but only if the message hasn't already been handled
  463.             if (!myIsHandled)
  464.                 QTApp_HandleContentClick(theWnd, &myMacEvent);
  465.             break;
  466.  
  467.         case WM_CHAR:
  468.             // do any application-specific key press handling
  469.             QTApp_HandleKeyPress((char)wParam);
  470.             break;
  471.  
  472.         case WM_PAINT: {
  473.             // do any application-specific drawing in the window
  474.                 PAINTSTRUCT        myPaintStruct;
  475.             
  476.                 BeginPaint(theWnd, &myPaintStruct);
  477.  
  478.                 // if the window contains an image, draw it using GraphicsImportDraw
  479.                 if (myWindowObject != NULL)
  480.                     if ((**myWindowObject).fGraphicsImporter != NULL)
  481.                         GraphicsImportDraw((**myWindowObject).fGraphicsImporter);
  482.             
  483.                 QTApp_Draw(theWnd, NULL);
  484.                 EndPaint(theWnd, &myPaintStruct);
  485.             }
  486.             break;
  487.  
  488.         case WM_MDIACTIVATE:
  489.             // activate or deactivate the movie controller in the specified window
  490.             QTFrame_ActivateController(theWnd, (HWND)theWnd == (HWND)lParam);
  491.             break;
  492.  
  493.         case WM_COMMAND: {
  494.  
  495.             switch (LOWORD(wParam)) {
  496.                             
  497.                 case IDM_FILESAVE:
  498.                 case IDM_FILESAVEAS:
  499.                     QTFrame_HandleFileMenuItem(theWnd, LOWORD(wParam));
  500.                     break;
  501.  
  502.                 case IDM_EDITUNDO:
  503.                 case IDM_EDITCUT:
  504.                 case IDM_EDITCOPY:
  505.                 case IDM_EDITPASTE:
  506.                 case IDM_EDITCLEAR:
  507.                 case IDM_EDITSELECTALL:
  508.                 case IDM_EDITSELECTNONE:
  509.                     QTFrame_HandleEditMenuItem(theWnd, LOWORD(wParam));
  510.                     break;
  511.                     
  512.                 default:
  513.                     // do any application-specific menu handling
  514.                     QTApp_HandleMenu((UInt16)LOWORD(wParam));
  515.                     break;
  516.             }
  517.             
  518.             break;
  519.         }    // case WM_COMMAND
  520.  
  521.         case WM_GETMINMAXINFO:
  522.             QTFrame_CalcWindowMinMaxInfo(theWnd, (LPMINMAXINFO)lParam);
  523.             return(0);
  524.  
  525.         case WM_CLOSE:
  526.             // prepare to close the window, making sure that any changed data is saved or explicitly discarded;
  527.             // we can still cancel the window closing here
  528.             if (myWindowObject != NULL) {
  529.             
  530.                 // if the window's data is "dirty", give the user a chance to save it
  531.                 if ((**myWindowObject).fIsDirty) {
  532.                     int            myItem;
  533.                     char        myText[256];
  534.                     UINT        myAction;
  535.         
  536.                     // get the title of the window
  537.                     GetWindowText(theWnd, myText, sizeof(myText));
  538.         
  539.                     // specify the action
  540.                     myAction = gShuttingDown ? IDS_SAVEONQUIT : IDS_SAVEONCLOSE;
  541.         
  542.                     // display the "Save changes" dialog box
  543.                     myItem = QTFrame_ShowCautionAlert(theWnd, myAction, MB_ICONEXCLAMATION, MB_YESNOCANCEL, gAppName, myText);
  544.                     switch (myItem) {
  545.                         case kSaveChanges:
  546.                             // save the data in the window
  547.                             QTFrame_UpdateMovieFile(theWnd);
  548.                             break;
  549.                             
  550.                         case kCancelClose:
  551.                             // do not close the window and do not quit the application
  552.                             gShuttingDown = false;
  553.                             return(0);
  554.                         
  555.                         case kDontSaveChanges:
  556.                             // discard any unsaved changes (that is, don't do anything)
  557.                             break;
  558.                             
  559.                         default:
  560.                             // unexpected item selected; just return
  561.                             return(0);
  562.                     }
  563.                 }
  564.             } // if (myWindowObject != NULL)
  565.             
  566.             // if we got to this point, it's okay to close and destroy the window
  567.             SendMessage(ghWndMDIClient, WM_MDIDESTROY, (WPARAM)theWnd, 0L);
  568.             break;
  569.  
  570.         case WM_DESTROY:
  571.             // when we get this message,
  572.             // the window has been removed from the screen and its associated data must be destroyed
  573.             if (myWindowObject != NULL)
  574.                 QTFrame_CloseWindowObject(myWindowObject);
  575.         
  576.             SetWindowLong(theWnd, GWL_USERDATA, 0);
  577.  
  578.             // destroy the port association
  579.             DestroyPortAssociation((CGrafPtr)GetHWNDPort(theWnd));
  580.             
  581.             break;
  582.     }
  583.  
  584.     return(DefMDIChildProc(theWnd, theMessage, wParam, lParam));
  585. }
  586.  
  587.  
  588. //////////
  589. //
  590. // QTFrame_QuitFramework
  591. // Do any framework-specific shut-down.
  592. //
  593. //////////
  594.  
  595. void QTFrame_QuitFramework (void)
  596. {
  597.     // set our global flag to indicate we're shutting down
  598.     gShuttingDown = true;
  599.     
  600.     // do application-specific processing that must occur before movie windows are closed
  601.     QTApp_Stop(kStopAppPhase_BeforeDestroyWindows);
  602.     
  603.     // close all open movie windows; note that the user can cancel the shutting down
  604.     QTFrame_CloseMovieWindows();
  605.     
  606.     // close the frame window, if we're still shutting down
  607.     if (gShuttingDown)
  608.         SendMessage(ghWnd, WM_CLOSE, 0, 0L);
  609. }
  610.  
  611.  
  612. //////////
  613. //
  614. // QTFrame_OpenCommandLineMovies
  615. // Parse the command line when the application first starts up and
  616. // open as movie documents any files specified on the command line.
  617. //
  618. // Based on the routine ParseCmdLinePriv in GraphicImporter.c.
  619. //
  620. //////////
  621.  
  622. void QTFrame_OpenCommandLineMovies (LPSTR theCmdLine)
  623. {
  624. #pragma unused(theCmdLine)
  625.     LPSTR                myCmdLine;
  626.     FSSpec                myFSSpec;
  627.     SHFILEINFO            myFileInfo;
  628.     
  629.     // get the command line for the current process
  630.     myCmdLine = GetCommandLine();
  631.  
  632.     // parse the command line
  633.     if (*myCmdLine) {
  634.         LPSTR            myTempLine;
  635.         
  636.         // the string preceding any white space is the name of the module (that is, the application)
  637.         myTempLine = strchr(myCmdLine, ' ');
  638.         if (myTempLine) {
  639.             myCmdLine = myTempLine;                  // skip the name of the application
  640.             while (*myCmdLine == ' ')
  641.                 myCmdLine++;                        // skip spaces to end of string or to first command
  642.  
  643.             while (*myCmdLine != '\0') {
  644.                 char     myFileName[MAX_PATH];
  645.                 char     myTempName[MAX_PATH];
  646.                 char     myBuffName[MAX_PATH];
  647.                 int     myIndex;
  648.                 
  649.                 // read thru the remaining string to find file names
  650.                 for (myIndex = 0; *myCmdLine != '\0'; myIndex++, myCmdLine++) {
  651.                     // if we encounter a space character, it might be a filename delimiter or a space in the filename;
  652.                     // we'll try to open the filename we have so far to see whether it's a valid filename; if not, the
  653.                     // space must be part of the filename we're constructing
  654.                     if (*myCmdLine == ' ') {
  655.                         HANDLE                myFindFile;
  656.                         WIN32_FIND_DATA        myFile;
  657.                     
  658.                         myTempName[myIndex] = '\0';
  659.                         strcpy(myBuffName, myTempName);
  660.                         
  661.                         myFindFile = FindFirstFile(myBuffName, &myFile);
  662.                         if (myFindFile != INVALID_HANDLE_VALUE) {
  663.                             // we found a file having the specified name; close our file search and
  664.                             // break out of our character-gobbling loop (since we've got a valid filename)
  665.                             FindClose(myFindFile);
  666.                             break;
  667.                         }
  668.                     }
  669.                 
  670.                     // if we made it here, *myCmdLine is part of the filename (possibly a space)
  671.                     myFileName[myIndex] = myTempName[myIndex] = *myCmdLine;
  672.                 }
  673.                 
  674.                 if (*myCmdLine != '\0')
  675.                     myCmdLine++;
  676.                 
  677.                 // add a terminating NULL character
  678.                 myFileName[myIndex] = '\0';
  679.  
  680.                 // make sure the filename picks out a QuickTime movie
  681.                 SHGetFileInfo(myFileName, (DWORD)0, &myFileInfo, sizeof(myFileInfo), SHGFI_TYPENAME);
  682.                 if (strcmp(myFileInfo.szTypeName, gMovieType) != 0)
  683.                     continue;
  684.                 
  685.                 // make an FSSpec record
  686.                 NativePathNameToFSSpec(myFileName, &myFSSpec, 0L);
  687.  
  688.                 // open the file in a movie window
  689.                 QTFrame_OpenMovieInWindow(NULL, &myFSSpec);
  690.             }
  691.  
  692.         } else
  693.             myCmdLine += strlen(myCmdLine);           // point to NULL
  694.     }
  695. }
  696.  
  697.  
  698. //////////
  699. //
  700. // QTFrame_CreateMovieWindow
  701. // Create a new window to display the movie in.
  702. //
  703. //////////
  704.  
  705. WindowReference QTFrame_CreateMovieWindow (void)
  706. {
  707.     WindowReference            myWindow = NULL;
  708.  
  709.     gWeAreCreatingWindow = true;
  710.     
  711.     // create a new window to display the movie in
  712.     myWindow = CreateWindowEx(WS_EX_MDICHILD,
  713.                                gChildName,
  714.                                "",
  715.                                0,
  716.                                CW_USEDEFAULT,
  717.                                CW_USEDEFAULT,
  718.                                CW_USEDEFAULT,
  719.                                CW_USEDEFAULT,
  720.                                ghWndMDIClient, 
  721.                                NULL,
  722.                                ghInst,
  723.                                0);
  724.     
  725.     // CreateWindowEx sends a WM_CREATE message to the window being created;
  726.     // we'll call QTFrame_CreateWindowObject when processing that message
  727.     
  728.     gWeAreCreatingWindow = false;
  729.  
  730.     return(myWindow);
  731. }
  732.  
  733.  
  734. //////////
  735. //
  736. // QTFrame_DestroyMovieWindow
  737. // Close the specified movie window.
  738. //
  739. //////////
  740.  
  741. void QTFrame_DestroyMovieWindow (WindowReference theWindow)
  742. {
  743. #pragma unused(theWindow)
  744.  
  745.     HWND                myChild = NULL;
  746.     
  747.     // close the active child window
  748.     myChild = (HWND)SendMessage(ghWndMDIClient, WM_MDIGETACTIVE, 0, 0L);
  749.     if (IsWindow(myChild))
  750.         SendMessage(myChild, WM_CLOSE, 0L, 0L);
  751. }
  752.  
  753.  
  754. //////////
  755. //
  756. // QTFrame_GetDisplayName
  757. // Given a full pathname, return the part that trails the rightmost path separator,
  758. // in long file name format (not in 8.3 format).
  759. //
  760. //////////
  761.  
  762. void QTFrame_GetDisplayName (char *thePathName, char *theDispName)
  763. {
  764.     SHFILEINFO            myFileInfo;
  765.     DWORD                myResult;
  766.     
  767.     myResult = SHGetFileInfo(thePathName, (DWORD)0, &myFileInfo, sizeof(myFileInfo), SHGFI_DISPLAYNAME);
  768.     if (myResult != 0) {
  769.         // SHGetFileInfo successful
  770.         strcpy(theDispName, myFileInfo.szDisplayName);
  771.     } else {
  772.         // SHGetFileInfo not successful, so find the basename ourselves
  773.         short    myLength = 0;
  774.         short    myIndex;
  775.  
  776.         // get the length of the pathname
  777.         myLength = strlen(thePathName);
  778.         
  779.         // find the position of the rightmost path separator in thePathName
  780.         if (strchr(thePathName, kWinFilePathSeparator) != NULL) {
  781.     
  782.             myIndex = myLength - 1;
  783.             while (thePathName[myIndex] != kWinFilePathSeparator)
  784.                 myIndex--;
  785.                 
  786.             // calculate the length of the basename
  787.             myLength = myLength - myIndex - 1;
  788.     
  789.         } else {
  790.             // there is no rightmost path separator in thePathName;
  791.             // set myIndex so that myIndex + 1 == 0, for the call to BlockMove below
  792.             myIndex = -1;
  793.         }
  794.         
  795.         // copy into theDispName the substring of thePathName from myIndex + 1 to the end
  796.         BlockMove(&thePathName[myIndex + 1], theDispName, myLength);
  797.         theDispName[myLength] = '\0';
  798.     }
  799. }
  800.  
  801.  
  802. //////////
  803. //
  804. // QTFrame_ShowAboutBox 
  805. // Display and manage the About dialog box.
  806. //
  807. //////////
  808.  
  809. void QTFrame_ShowAboutBox (void)
  810. {
  811.     DialogBox(ghInst, MAKEINTRESOURCE(IDD_ABOUT), ghWnd, (DLGPROC)QTFrame_DialogProcedure);
  812. }
  813.  
  814.  
  815. //////////
  816. //
  817. // QTFrame_ShowCautionAlert 
  818. // Display and manage a caution alert.
  819. //
  820. // Based on ShowUserMessage by Stephen Chernicoff, in his WiniEdit application
  821. // (as described in the book "From Mac to Windows" on CodeWarrior reference CD).
  822. //
  823. //////////
  824.  
  825. int QTFrame_ShowCautionAlert (HWND theWnd, UINT theID, UINT theIconStyle, UINT theButtonStyle, LPSTR theTitle, LPSTR theArgument)
  826. {
  827.     char            myTemplate[kAlertMessageMaxLength];
  828.     char            myText[kAlertMessageMaxLength];
  829.     UINT            myStyle;
  830.     int                myItem;
  831.     
  832.     // beep, to get the user's attention (just like CautionAlert on MacOS)
  833.     QTFrame_Beep();
  834.     
  835.     // load the message text template from a resource
  836.     LoadString(ghInst, theID, myTemplate, sizeof(myTemplate));
  837.     
  838.     // insert argument into the message text template, to get the message text
  839.     wsprintf(myText, myTemplate, theArgument);
  840.     
  841.     // set the dialog box style
  842.     myStyle = theIconStyle | theButtonStyle | MB_APPLMODAL | MB_SETFOREGROUND;
  843.  
  844.     // display the dialog box
  845.     myItem = MessageBox(theWnd, myText, theTitle, myStyle);
  846.     
  847.     return(myItem);
  848. }
  849.  
  850.  
  851. //////////
  852. //
  853. // QTFrame_DialogProcedure 
  854. // Dialog callback procedure.
  855. //
  856. //////////
  857.  
  858. static UINT APIENTRY QTFrame_DialogProcedure (HWND theDialog, UINT theMessage, WPARAM wParam, LPARAM lParam)
  859. {
  860.     BOOL    isHandled = false;
  861.  
  862.     switch (theMessage) {
  863.     
  864.         case WM_INITDIALOG: {
  865.             Point            myPoint;
  866.             long            myWidth;
  867.             long            myHeight;
  868.             RECT            myRect;
  869.             RECT            myDeskRect;
  870.             HWND            myWindow;
  871.             OPENFILENAME    *myOFNPtr = (OPENFILENAME *)lParam;
  872.             
  873.             myWindow = theDialog;
  874.                 
  875.             // check whether theDialog is the Open File common dialog box
  876.             
  877.             // we need to do this because, for the Open File dialog box, theDialog isn't
  878.             // the actual visible dialog box, but an invisible child of the visible dialog box;
  879.             // for WM_INITDIALOG, lParam is the address of the structure passed to GetOpenFileName,
  880.             // so we can just look for the value we previously put into the lCustData field
  881.             // to make sure that we've got the correct dialog.
  882.             if (myOFNPtr != NULL)
  883.                 if (myOFNPtr->lCustData == kOpenDialogCustomData)
  884.                     myWindow = GetParent(theDialog);
  885.                 
  886.             // center the dialog window on the screen
  887.             GetWindowRect(myWindow, &myRect);
  888.             myWidth = myRect.right - myRect.left;
  889.             myHeight = myRect.bottom - myRect.top;
  890.             GetWindowRect(GetDesktopWindow(), &myDeskRect);
  891.             myPoint.h = (short)((myDeskRect.right + myDeskRect.left)/2 - myWidth/2);
  892.             myPoint.v = (short)((myDeskRect.top + myDeskRect.bottom)/3 - myHeight/3);
  893.             SetWindowPos(myWindow, 0, myPoint.h, myPoint.v, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  894.             
  895.             // let Windows set the input focus
  896.             isHandled = true;
  897.             break;
  898.         }
  899.         
  900.         case WM_CLOSE:
  901.             EndDialog(theDialog, IDOK);
  902.             isHandled = true;
  903.             break;
  904.         
  905.         case WM_COMMAND:
  906.             switch (LOWORD(wParam)) {
  907.                 case IDOK:
  908.                     EndDialog(theDialog, IDOK);
  909.                     isHandled = true;
  910.                     break;
  911.                 default:
  912.                     isHandled = false;
  913.                     break;
  914.             }
  915.             break;
  916.         
  917.         default:
  918.             isHandled = false;
  919.             break;
  920.     }
  921.  
  922.     return(isHandled);
  923. }
  924.  
  925.  
  926. //////////
  927. //
  928. // QTFrame_CalcWindowMinMaxInfo 
  929. // Get minimum and maximum possible size of this window.
  930. //
  931. //////////
  932.  
  933. static void QTFrame_CalcWindowMinMaxInfo (HWND theWnd, LPMINMAXINFO lpMinMax)
  934. {
  935.     WindowObject                myWindowObject = NULL;
  936.     Movie                        myMovie = NULL;
  937.     MovieController                myMC = NULL;
  938.     GraphicsImportComponent        myImporter = NULL;
  939.     Rect                        myRect;
  940.     ComponentResult                myErr = noErr;
  941.     
  942.     myWindowObject = QTFrame_GetWindowObjectFromWindow(theWnd);
  943.     if (myWindowObject != NULL) {
  944.         myMC = (**myWindowObject).fController;
  945.         myMovie = (**myWindowObject).fMovie;
  946.         myImporter = (**myWindowObject).fGraphicsImporter;
  947.     }
  948.     
  949.     // we're expecting a window with either an image or a movie
  950.     if ((myImporter == NULL) && (myMovie == NULL))
  951.         return;
  952.  
  953.     if (myImporter != NULL) {
  954.         // this window contains an image; we currently don't allow images to be resized,
  955.         // so we return both min and max rectangles set to the current image size, plus
  956.         // the appropriate window frame and caption sizes
  957.         myErr = GraphicsImportGetBoundsRect(myImporter, &myRect);
  958.         if (myErr == noErr) {
  959.             lpMinMax->ptMinTrackSize.x = myRect.right + (2 * GetSystemMetrics(SM_CXFRAME));
  960.             lpMinMax->ptMinTrackSize.y = myRect.bottom + (2 * GetSystemMetrics(SM_CXFRAME)) + GetSystemMetrics(SM_CYCAPTION);                                // caption height
  961.         
  962.             lpMinMax->ptMaxTrackSize.x = lpMinMax->ptMinTrackSize.x;
  963.             lpMinMax->ptMaxTrackSize.y = lpMinMax->ptMinTrackSize.y;
  964.             
  965.             lpMinMax->ptMaxSize.x = lpMinMax->ptMinTrackSize.x;
  966.             lpMinMax->ptMaxSize.y = lpMinMax->ptMinTrackSize.y;
  967.         }
  968.     }
  969.     
  970.     if (myMovie != NULL) {
  971.         // this window contains a movie; we currently don't allow movies to be resized
  972.         // except using the grow box in the movie controller bar; so set the min and max
  973.         // tracking rectangles to be the current size of the movie window
  974.         GetMovieBox(myMovie, &myRect);
  975.         if (myMC != NULL)
  976.             if (MCGetVisible(myMC))
  977.                 MCGetControllerBoundsRect(myMC, &myRect);
  978.                 
  979.         lpMinMax->ptMinTrackSize.x = myRect.right + (2 * GetSystemMetrics(SM_CXFRAME));
  980.         lpMinMax->ptMinTrackSize.y = myRect.bottom + (2 * GetSystemMetrics(SM_CXFRAME)) + GetSystemMetrics(SM_CYCAPTION) - 1;                                // caption height
  981.     
  982.         lpMinMax->ptMaxTrackSize.x = lpMinMax->ptMinTrackSize.x;
  983.         lpMinMax->ptMaxTrackSize.y = lpMinMax->ptMinTrackSize.y;
  984.         
  985.         lpMinMax->ptMaxSize.x = lpMinMax->ptMinTrackSize.x;
  986.         lpMinMax->ptMaxSize.y = lpMinMax->ptMinTrackSize.y;
  987.     }
  988. }
  989.  
  990.  
  991.